package nl.jjsoft.airlock.view.presenters
{
	import flash.desktop.Clipboard;
	import flash.desktop.ClipboardFormats;
	import flash.display.DisplayObject;
	import flash.display.NativeMenu;
	import flash.display.NativeMenuItem;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	
	import mx.collections.ArrayCollection;
	import mx.controls.Alert;
	import mx.controls.List;
	import mx.controls.TextInput;
	import mx.core.Application;
	import mx.events.CloseEvent;
	import mx.events.ListEvent;
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.managers.PopUpManager;
	
	import nl.jjsoft.airlock.controller.ISafeController;
	import nl.jjsoft.airlock.controller.SettingsController;
	import nl.jjsoft.airlock.domain.Model;
	import nl.jjsoft.airlock.event.AccountEvent;
	import nl.jjsoft.airlock.utils.KeyBoardUtils;
	import nl.jjsoft.airlock.utils.ResourceFactory;
	import nl.jjsoft.airlock.view.Main;
	import nl.jjsoft.airlock.view.Settings;
	import nl.jjsoft.airlock.view.presenters.helpers.AccountPresenterHelper;
	import nl.jjsoft.airlock.vo.AccountVo;
	import nl.jjsoft.airlock.vo.GroupVO;
	
	// TODO Account and group related logic should be placed in separate helper classes for groups and accounts because
	// this logic is used at more than one place.
	public class MainPresenter extends AbstractPresenter
	{
		private static var logger:ILogger = Log.getLogger("MainPresenter");
		
		[Inject]
		public var model:Model;
		
		[Inject]
		public var settingsPresenter:SettingsPresenter;
		
		[Inject]
		public var safeController:ISafeController;

		[Inject]
		public var accountPresenterHelper:AccountPresenterHelper;
		
		[Inject]
		public var settingsController:SettingsController;
		
		[Inject]
		public var resourceFactory:ResourceFactory;
		
		private var createMenu:NativeMenu;		
		private var groupDeleteConfirmDialog:Alert;
		private var accountDeleteConfirmDialog:Alert;
		
		public function MainPresenter()
		{
			super(Main);
		}
		
		override protected function init():void {
			super.init();
			this.createAddMenu();
		}
		
		public function get view():Main {
			return this._view as Main;
		}
		
		override protected function setViewListeners():void {
			registerEventHandler(view.btnAdd, MouseEvent.CLICK, addButtonClicked, true);
			registerEventHandler(view.btnDelete, MouseEvent.CLICK, deleteClicked);
			registerEventHandler(view.btnSettings, MouseEvent.CLICK, settingsButtonClicked);
			registerEventHandler(view.groups, MouseEvent.CLICK, groupSelected, true);
			registerEventHandler(view.groups, ListEvent.CHANGE, groupSelected, true);
			registerEventHandler(view.groups, ListEvent.ITEM_DOUBLE_CLICK, groupsDoubleClicked, true);
			registerEventHandler(view.groups, ListEvent.ITEM_EDIT_END, groupsItemEditEnd, true);		
			registerEventHandler(view.groups, KeyboardEvent.KEY_DOWN, keyDownGroup, true);
			registerEventHandler(view.entries, MouseEvent.CLICK, accountSelected, true);
			registerEventHandler(view.entries, ListEvent.CHANGE, accountSelected, true);
			registerEventHandler(view.entries, MouseEvent.DOUBLE_CLICK, accountDoubleClicked, true);
			registerEventHandler(view.entries, ListEvent.ITEM_EDIT_END, accountItemEditEnd, true);
			registerEventHandler(view.entries, KeyboardEvent.KEY_DOWN, keyDownEntry, true);			
		}
		
		private function accountDoubleClicked(event:MouseEvent):void {
			var account:AccountVo = List(event.currentTarget).selectedItem as AccountVo;
			if (account.credentials.user_pass != null) {
				Clipboard.generalClipboard.setData(ClipboardFormats.TEXT_FORMAT, account.credentials.user_pass);
			}
		}
		
		private function accountItemEditEnd(event:ListEvent):void {
			logger.debug("entry item edit end with reason " + event.reason);
            var myEditor:TextInput = TextInput(event.currentTarget.itemEditorInstance);
            var newVal:String = myEditor.text;
            var account:AccountVo = event.currentTarget.editedItemRenderer.data;
            if (this.isAccountDirty(account, newVal)) {
            	account.name = newVal;
            	account.group_id = model.selectedGroup.id;
				account.id = safeController.saveAccount(account); 
				model.selectedAccount = account;
				dispatcher.dispatchEvent(new AccountEvent(AccountEvent.SET_FOCUS_USERNAME));
				// TODO Doing this stops event propagation for the accounteditform keyboard events
				event.stopImmediatePropagation();
            }            
			view.entries.editable = false;
			trace("in edit end");
		}
		
		private function isAccountDirty(oldItem:AccountVo, newName:String):Boolean {
			if (isNaN(oldItem.id)) {
				logger.debug("The newgroup with name [" + oldItem.name + "] has no id yet, thus is dirty.");
				return true;
			}
			
			if (oldItem.name != newName) {
				logger.debug("The name of the old item [" + oldItem.name + "] is different from the newly entered name [" + newName + "], item is dirty.");
			}
			
			return oldItem.name != newName;
		}
		
		public function settingsButtonClicked():void {
			settingsController.retrieveSettings();
			var _settings:Settings = PopUpManager.createPopUp(Application.application as DisplayObject, Settings, true) as Settings;
			PopUpManager.centerPopUp(_settings);
		}
		
		public function addButtonClicked(event:MouseEvent):void {
			createMenu.getItemByName("Account").enabled = model.selectedGroup != null;
			createMenu.display(event.target.stage, event.stageX, event.stageY);
		}
		
		private function groupSelected(event:Event):void {
			this.groupChanged(event);
			if (model.selectedGroup != null) {
				dispatcher.dispatchEvent(new AccountEvent(AccountEvent.HIDE_EDIT_FORM, true));
				view.entries.selectedItem = null;
			}
		}
		
		private function accountSelected(event:Event):void {
			this.accountChanged(event);
			if (model.selectedAccount != null) {
				dispatcher.dispatchEvent(new AccountEvent(AccountEvent.SHOW_EDIT_FORM, true));
			}
		}
		
		private function accountChanged(event:Event):void {
			model.selectedAccount = List(event.currentTarget).selectedItem as AccountVo;
		}
		
		public function createAddMenu():void {
			createMenu = new NativeMenu();
			var createGroupMenuItem:NativeMenuItem = new NativeMenuItem(resourceFactory.getResource("addmenu.group"), false);
			createGroupMenuItem.name = "Group";
			createGroupMenuItem.addEventListener(Event.SELECT, addGroup);
			createMenu.addItem(createGroupMenuItem);
			var createAccountMenuItem:NativeMenuItem = new NativeMenuItem(resourceFactory.getResource("addmenu.account"), false);
			createAccountMenuItem.name = "Account";			
			createAccountMenuItem.addEventListener(Event.SELECT, addAccount);
			createMenu.addItem(createAccountMenuItem);
		}
		
		private function addGroup(event:Event):void {
			var newGroup:GroupVO = new GroupVO();
			newGroup.name = "New Group";
			model.groups.addItem(newGroup);
			view.groups.editable = true;
			view.groups.editedItemPosition = {columnIndex:0, rowIndex:model.groups.length-1};
			dispatcher.dispatchEvent(new AccountEvent(AccountEvent.HIDE_EDIT_FORM, true));
		}
		
		private function addAccount(event:Event):void {
			var newAccount:AccountVo = new AccountVo();
			newAccount.name = "New Account";
			model.newAccount = newAccount;
			if (model.selectedGroup.passwords == null) {
				model.selectedGroup.passwords = new ArrayCollection();
			}
			model.selectedGroup.passwords.addItem(newAccount);
			view.entries.editable = true;
			view.entries.editedItemPosition = {columnIndex:0, rowIndex:model.selectedGroup.passwords.length-1};
			dispatcher.dispatchEvent(new AccountEvent(AccountEvent.NEW_ACCOUNT, true));
		}
		
		/**
		 * Deletes the selected group, or if an entry is selected, deletes the selected entry.
		 */
		public function deleteClicked():void {
			if (view.entries.selectedItem != null) {
				var account:AccountVo = view.entries.selectedItem as AccountVo;
				accountPresenterHelper.deleteAccount(account);			
			} else {
				deleteGroup();
			}
		}
		
		public function keyDownGroup(event:KeyboardEvent):void {
			if (KeyBoardUtils.rightPressed(event)) {
				view.focusManager.setFocus(view.entries);
				view.entries.selectedIndex = 0;
				model.selectedAccount = AccountVo(view.entries.selectedItem);
				dispatcher.dispatchEvent(new AccountEvent(AccountEvent.SHOW_EDIT_FORM, true));
			}
		}
		
		public function keyDownEntry(event:KeyboardEvent):void {
			if (KeyBoardUtils.leftPressed(event)) {
				model.selectedAccount = null;
				view.entries.selectedIndex = -1;
				view.focusManager.setFocus(view.groups);
				dispatcher.dispatchEvent(new AccountEvent(AccountEvent.HIDE_EDIT_FORM, true));	
			}
		}
		
		/** Groups related functionality **/
		public function groupsDoubleClicked(event:ListEvent):void {
			logger.debug("groups double clicked");
			view.groups.editable = true;
			view.groups.editedItemPosition = {columnIndex:0, rowIndex:event.rowIndex};
		}
		
		public function groupsItemEditEnd(event:ListEvent):void {
			logger.debug("groups item edit end with reason " + event.reason);
            var myEditor:TextInput = TextInput(event.currentTarget.itemEditorInstance);
            var newVal:String = myEditor.text;
            var group:GroupVO = event.currentTarget.editedItemRenderer.data;
            if (this.isGroupDirty(group, newVal)) {
            	group.name = newVal;
				safeController.saveGroup(group);
				model.selectedGroup = group;
            }            
			view.groups.editable = false;
		}
		
		private function isGroupDirty(oldItem:GroupVO, newName:String):Boolean {
			if (isNaN(oldItem.id)) {
				logger.debug("The newgroup with name [" + oldItem.name + "] has no id yet, thus is dirty.");
				return true;
			}
			
			if (oldItem.name != newName) {
				logger.debug("The name of the old item [" + oldItem.name + "] is different from the newly entered name [" + newName + "], item is dirty.");
			}
			
			return oldItem.name != newName;
		}
		
		public function groupChanged(event:Event):void {
			var selectedGroup:GroupVO = List(event.currentTarget).selectedItem as GroupVO;
			if (selectedGroup != null && model.selectedGroup != selectedGroup) {			
				model.selectedGroup = selectedGroup;
				model.selectedAccount = null;
				if (!model.selectedGroup.passwordsRetrieved()) {
					model.selectedGroup.passwords = safeController.getAccountsForGroup(model.selectedGroup);
				}
			}
		}
		
		public function deleteGroup():void {
			var selectedGroup:GroupVO = GroupVO(view.groups.selectedItem);
			logger.debug("Selected group = " + selectedGroup);
			if (selectedGroup != null) {
				groupDeleteConfirmDialog = Alert.show(resourceFactory.getResource("shared.areyousure"), resourceFactory.getResource("accountform.removegroup"), Alert.YES + Alert.NO, null, function close(event:CloseEvent):void {
					deleteGroupConfirmationClose(event, selectedGroup);				
					event.target.removeEventListener(CloseEvent.CLOSE, arguments.callee);
				});
			}
		}
		
		private function deleteGroupConfirmationClose(event:CloseEvent, selectedGroup:GroupVO):void {
			if (event.detail == Alert.YES) {
				if (safeController.deleteGroup(selectedGroup)) {
					model.groups.removeItemAt(model.groups.getItemIndex(selectedGroup));
					model.selectedGroup = null;
				}
			}
		}
		/** Groups related functionality **/
	}
}